/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.component.gateway.core.http.impl;

import info.peigen.hotpot.component.gateway.core.exception.GatewayBusinessException;
import info.peigen.hotpot.component.gateway.core.http.HttpClient;
import info.peigen.hotpot.component.gateway.core.http.OkHttpClientUtil;
import info.peigen.hotpot.component.gateway.core.http.enums.HttpType;
import info.peigen.hotpot.component.gateway.core.http.request.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.noear.solon.annotation.Component;

import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <b>(CommonHttpClient)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2019-05-28
 */
@Slf4j
@Component
public class CommonHttpClient implements HttpClient {

    public static final Integer CONNECT_TIMEOUT = 1;
    public static final Integer READ_TIMEOUT    = 3;

    @Override
    public HttpType httpType() {
        return HttpType.COMMON;
    }

    @Override
    public String send(HttpRequest request) throws Exception {
        switch (request.getMethodType()) {
            case GET:
                return doGet(request);
            case POST:
                return doPost(request);
            default:
                log.warn("请求异常：没找到正确的请求方式[默认POST]，HttpRequest={}", request);
                return null;
        }

    }

    private String doGet(HttpRequest req) throws Exception {

        OkHttpClient.Builder builder = OkHttpClientUtil.getInstance().newBuilder();

        builder
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);

        OkHttpClient client = builder.build();

        Request.Builder reqBuild = new Request.Builder();
        reqBuild.addHeader("accept", "*/*");
        reqBuild.addHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        reqBuild.addHeader("connection", "Keep-Alive");
        HttpUrl.Builder urlBuilder = HttpUrl.parse(req.getRequestUrl()).newBuilder();

        req.getRequestMessageMap().values().removeIf(Objects::isNull);
        req.getRequestMessageMap().entrySet().stream()
                .forEach(map -> urlBuilder.addQueryParameter(map.getKey(), map.getValue()));

        reqBuild.url(urlBuilder.build());

        long callStartTime = System.currentTimeMillis();
        try (Response response = client.newCall(reqBuild.build()).execute()) {
            return response.body().string();
        } catch (Exception e) {
            log.error("get请求发生错误", e);

            if (e instanceof SocketTimeoutException) {
                throw e;
            }

            throw new GatewayBusinessException(e.getMessage(), e.getCause());
        }

    }

    private String doPost(HttpRequest req) throws Exception {
        OkHttpClient client = OkHttpClientUtil.getInstance().newBuilder()
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                .build();

        FormBody.Builder formBodyBuilder = new FormBody.Builder(Charset.defaultCharset());

        req.getRequestMessageMap().values().removeIf(Objects::isNull);

        req.getRequestMessageMap().entrySet().stream().forEach(msg -> {
            formBodyBuilder.addEncoded(msg.getKey(), msg.getValue());
        });

        RequestBody formBody = formBodyBuilder.build();

        Request request = new Request.Builder()
                .url(req.getRequestUrl())
                .post(formBody)
                .build();

        long callStartTime = System.currentTimeMillis();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        } catch (Exception e) {
            log.error("post请求发生错误", e);

            if (e instanceof SocketTimeoutException) {
                throw e;
            }

            throw new GatewayBusinessException(e.getMessage(), e.getCause());
        }
    }

}